package Session;

import Cart.Cart;
import DAO.DAO;
import DTO.Address;
import DTO.Customer;
import DTO.Item;
import DTO.Order;
import DTO.Payment;
import DTO.ShippingMethod;
import Exception.EmptySet;
import Exception.KwickKioskDBException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.Session;

/**
 * this class handles the session of application by maintaining session objects 
 * @author tejinder
 * @see Session
 */
public class SessionManager {

    protected Customer customer = null;
    protected int cutomerId = 0;

    ;
    protected boolean loggedIn = false;
    protected Cart cart = null;
    protected DAO dao = null;
    protected List<Item> searchItemsInSession = null;
    protected boolean onPathToPurchase = false;
    protected Address shipaddressForOrder = null;
    protected ShippingMethod shipMethodForOrder = null;
    protected Item singleItemOnPathToPurchase;
    protected List<Item> cartItemsInSession;
    protected double shipCostOrder = 0.0;
    protected ArrayList<Payment> paymentList = null;
    protected Payment orderPymtDet = null;
    protected Order order = null;
    protected List<Item> listDiscountCart = null;
    protected Double cartSubTotal = 0.00;
    protected Double cartTotal = 0.00;
    protected Double orderTotal = 0.00;
    protected Double orderTax = 0.00;
    protected Double totalDiscount = 0.00;

    /**
     * constructor for this class
     * @param dao
     */
    public SessionManager(DAO dao) {
        this.dao = dao;
        customer = new Customer();
        loggedIn = false;
        cart = new Cart(dao, this);
        shipaddressForOrder = new Address();
        shipMethodForOrder = new ShippingMethod();
        orderPymtDet = new Payment();
        listDiscountCart = new ArrayList<Item>();
        paymentList = new ArrayList<Payment>();
        cartItemsInSession = null;
        order = new Order();
    }

    /**
     * constructor for this class
     * @param cust
     * @param logIn
     */
    public SessionManager(Customer cust, boolean logIn) {
        customer = cust;
        loggedIn = logIn;
    }

    //GETTERS AND SETTERS ------------------------------------------------------
    /**
     * gets customer id
     * @return
     */
    public int getCustomerId() {
        return customer.getStoreCardNumber();
    }

    public double getOrderDiscount(){
        return order.getOrderDiscount();
    }
    public Double getOrderTax() {
        return orderTax;
    }

    public void setOrderTax(Double orderTax) {
        this.orderTax = orderTax;
    }

    /**
     * gets cart in session
     * @return
     */
    public Cart getCart() {
        return cart;
    }

    /**
     * gets customer object
     * @return
     */
    public Customer getCustomer() {
        return customer;
    }

    /**
     * sets the customer object
     * @param aCustomerId the customerId to set
     */
    public boolean setCustomer(String storeCard) throws KwickKioskDBException {
        try {

            customer = dao.getCustomer(Integer.parseInt(storeCard));
            if (customer == null) {
                return false;
            }
        } catch (EmptySet ex) {
            System.out.println("card not found");
            return false;
        } catch (KwickKioskDBException kkdb) {
            System.out.println("database down"); //NEED TO IMPLEMENT THIS FOR REAL
            return false;
        }

        loggedIn = true;
        cart.calculateTotals();
        return true;
    }

    /**
     * gets true/false for logged in or logged out
     * @return the loggedIn
     */
    public boolean getLoggedIn() {
        return loggedIn;
    }

    /**
     * sets logged in or logged out
     * @param loggedIn the loggedIn to set
     */
    public void setLoggedIn(boolean loggedIn) {
        this.loggedIn = loggedIn;
    }

    /**
     * gets customer id
     * @return the cutomerId
     */
    public int getCutomerId() {
        return cutomerId;
    }

    /**
     * sets customer id
     * @param cutomerId the cutomerId to set
     */
    public void setCutomerId(int cutomerId) {
        this.cutomerId = cutomerId;
    }

    /**
     * gets search result item from  session
     * @return the searchItemsInSession
     */
    public List<Item> getSearchItemsInSession() {
        return searchItemsInSession;
    }

    /**
     * sets search result items in session
     * @param searchItemsInSession the searchItemsInSession to set
     */
    public void setSearchItemsInSession(List<Item> itemsInSession) {
        this.searchItemsInSession = itemsInSession;
    }

    /**
     * determines if customer is across checkout or on cart, true: if after checkout else false
     * @return the onPathToPurchase
     */
    public boolean isOnPathToPurchase() {
        return onPathToPurchase;
    }

    /**
     * sets to true if customer is passed checkout else set it to false 
     * @param onPathToPurchase the onPathToPurchase to set
     */
    public void setOnPathToPurchase(boolean onPathToPurchase) {
        this.onPathToPurchase = onPathToPurchase;
    }

    /**
     * gets the latest selected item
     * @return the singleItemOnPathToPurchase
     */
    public Item getSingleItemOnPathToPurchase() {
        return singleItemOnPathToPurchase;
    }

    /**
     * sets latest selected item 
     * @param singleItemOnPathToPurchase the singleItemOnPathToPurchase to set
     */
    public void setSingleItemOnPathToPurchase(Item singleItemOnPathToPurchase) {
        this.singleItemOnPathToPurchase = singleItemOnPathToPurchase;
    }

    /**
     * gets items present in cart from session
     * @return the cartItemsInSession
     */
    public List<Item> getCartItemsInSession() {
        return cartItemsInSession;
    }

    /**
     * sets cart items in session
     * @param cartItemsInSession the cartItemsInSession to set
     */
    public void setCartItemsInSession(List<Item> cartItemsInSession) {
        this.cartItemsInSession = cartItemsInSession;
    }

    /**
     * gets ship address
     * @return the shipaddressForOrder
     */
    public Address getShipaddressForOrder() {
        return shipaddressForOrder;
    }

    /**
     * sets ship address
     * @param shipaddressForOrder the shipaddressForOrder to set
     */
    public void setShipaddressForOrder(Address shipaddressForOrder) {
        this.shipaddressForOrder = shipaddressForOrder;
    }

    /**
     * gets shipping method selected for order
     * @return the shipMethodForOrder
     */
    public ShippingMethod getShipMethodForOrder() {
        return shipMethodForOrder;
    }

    /**
     * sets shipping method selected for order
     * @param shipMethodForOrder the shipMethodForOrder to set
     */
    public void setShipMethodForOrder(ShippingMethod shipMethodForOrder) throws KwickKioskDBException {
        this.shipMethodForOrder = shipMethodForOrder;
        shipCostOrder = shipMethodForOrder.getCost();
        cart.setShippingCost(shipCostOrder);
    }

    /**
     * gets selected ship method cost
     * @return the shipCostOrder
     */
    public double getShipCostOrder() {
        return shipCostOrder;
    }

    /**
     * sets selected ship method cost 
     * @param shipCostOrder the shipCostOrder to set
     */
    public void setShipCostOrder(double shipCostOrder) {
        this.shipCostOrder = shipCostOrder;
    }

    /**
     * gets payment details from session
     * @return the orderPymtDet
     */
    public Payment getOrderPymtDet() {
        return orderPymtDet;
    }

    /**
     * sets payment details 
     * @param orderPymtDet the orderPymtDet to set
     */
    public void setOrderPymtDet(Payment orderPymtDet) {
        this.orderPymtDet = orderPymtDet;
    }

    /**
     * gets order data transfer object
     * @return the order
     */
    public Order getOrder() {
        return order;
    }

    /**
     * sets order data transfer object 
     * @param order the order to set
     */
    public void setOrder(Order order) {
        this.order = order;
    }

    /**
     * gets current discounted items in session 
     * @return the listDiscountCart
     */
    public List<Item> getListDiscountCart() {
        return listDiscountCart;
    }

    /**
     * sets current discounted items in session 
     * @param listDiscountCart the listDiscountCart to set
     */
    public void setListDiscountCart(List<Item> listDiscountCart) {
        this.listDiscountCart = listDiscountCart;
    }

    /**
     * gets cart subtotal 
     * @return the cartSubTotal
     */
    public Double getCartSubTotal() {
        return cartSubTotal;
    }

    /**
     * sets cart subtotal 
     * @param cartSubTotal the cartSubTotal to set
     */
    public void setCartSubTotal(Double cartSubTotal) {
        this.cartSubTotal = cartSubTotal;
    }

    /**
     * gets payment list
     * @return
     */
    public ArrayList<Payment> getPaymentList() {
        return paymentList;
    }

    // FUNCTIONALITY------------------------------------------------------------
    /**
     *
     * @param upc
     */
    public void searchByUPC(String upc) throws KwickKioskDBException {
        cart.searchByUPC(upc);
    }

    /**
     *
     * @param ctid
     */
    public void searchByCategory(int ctid) throws KwickKioskDBException {
        cart.searchByCategory(ctid);
    }

    public void searchByKeyword(String keyword, String criteria) throws KwickKioskDBException{
        cart.searchByKeyword(keyword, criteria);
    }

    /**
     *
     * @param item
     * @param qty
     */
    public void addItemToCart(Item item, int qty) throws KwickKioskDBException {
        cart.addItem(item, qty);
    }

    /**
     * resets objects after logging out
     */
    public void logout() throws KwickKioskDBException {
        customer = new Customer();
        loggedIn = false;
        cart.calculateTotals();
    }

    /**
     *  sets payment details
     * @param pymnt
     */
    public void addPayment(Payment pymnt) {
        paymentList.add(pymnt);
    }

    /**
     *  checks payment restrictions
     * @return
     */
    public boolean enoughPayment() {
        if (totalDue() <= 0.0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * gets paid amount 
     * @return
     */
    public double totalPaid() {
        double hasPaid = 0.0;
        for (Payment pay : paymentList) {
            hasPaid += pay.getAmount();
        }
        return hasPaid;
    }

    /**
     * gets total due
     * @return
     */
    public double totalDue() {


        DecimalFormat formatter = new DecimalFormat(".00");
        BigDecimal bigD = new BigDecimal(formatter.format(cart.getTotal() - totalPaid()));

        return (bigD.doubleValue());
    }

    /**
     * this method processes store order
     */
    public void fullfillOrder() {
        String date = new Date().toString();
        for (int i = 0; i != cart.getItemsInCart().size(); i++) {
            int cartItemQty = cart.getItemsInCart().get(i).getQty();
            int dbQty = quantityAvailable(cart.getItemsInCart().get(i).getUpc());
            cart.getItemsInCart().get(i).setNewQtyInStore(dbQty-cartItemQty);
        }
        order = new Order(cart.getSubtotal(), cart.getTaxAmount(),
                cart.getTotalDiscount(), cart.getOrderDiscount(),
                cart.getStoreCardDiscount(), "WebStore", date, cart.getItemsInCart(), paymentList);
        System.out.println("total item: " + cart.getTotalNumItems());
        order.setGrandTotal(cart.getTotal());
        try {
            int oid = dao.makeStoreOrder(order);
            order.setID(oid);
        } catch (KwickKioskDBException ex) {
            Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        cart = new Cart(dao, this);
        paymentList = new ArrayList<Payment>();
    }

     /**
     * this method processes desktop order
     */
    public boolean fullfillDesktopOrder() {
        String date = new Date().toString();

        for (int i = 0; i != cart.getItemsInCart().size(); i++) {
            int cartItemQty = cart.getItemsInCart().get(i).getQty();
            int dbQty = quantityAvailable(cart.getItemsInCart().get(i).getUpc());
            cart.getItemsInCart().get(i).setNewQtyInStore(dbQty-cartItemQty);
        }
        order = new Order(date, cart.getSubtotal(), cart.getTaxAmount(), cart.getShippingCost(),
                cart.getTotalDiscount(), cart.getOrderDiscount(),
                cart.getStoreCardDiscount(), "WebStore", shipMethodForOrder.getID(), customer.getStoreCardNumber(),
                shipaddressForOrder.getID(), cart.getItemsInCart(), paymentList);
        System.out.print("Order ids (shopmeth, custid, shipadd) = ");
        System.out.println(shipMethodForOrder.getID()+ customer.getStoreCardNumber()+
                shipaddressForOrder.getID());
        System.out.println("total item: " + cart.getTotalNumItems());
        order.setGrandTotal(cart.getTotal());
        int oid = -1;
        try {
            oid = dao.makeDesktopOrder(order);
            order.setID(oid);
        } catch (KwickKioskDBException ex) {
            Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        cart = new Cart(dao, this);
        paymentList = new ArrayList<Payment>();
        if (oid != -1){
            return true;
        }
        else
            return false;
    }
/**
 * Find item quantity in database
 * @param upc Item UPC code
 * @return available Item quantity as integer
 */
     public int quantityAvailable(String upc){
        int inStore = 0;
        try {
            inStore = dao.getItemQtyInStore("Webstore", upc);
        } catch (KwickKioskDBException ex) {
            Logger.getLogger(SessionManager.class.getName()).log(Level.SEVERE, null, ex);
            // Implement connection down function
        }
        return inStore;
    }

    public void setCartTotal(double total){
        cartTotal = total;
    }


    /**
     * clears the session variables once user is logged out
     */
    public void clearSession() throws KwickKioskDBException {

        //clearing session
        setLoggedIn(false);
        setOnPathToPurchase(false);
        setShipCostOrder(0.00);
        setOrderPymtDet(null);
        setCutomerId(0);
        setShipaddressForOrder(null);
        setShipMethodForOrder(null);
        setCartSubTotal(0.00);
        setCartTotal(0.00);
        // setNumItemsInSession(0);
        setOrder(null);
        cart = new Cart(dao, this);

    }

    /**
     * @return the totalDiscount
     */
    public Double getTotalDiscount() {
        return totalDiscount;
    }

    /**
     * @param totalDiscount the totalDiscount to set
     */
    public void setTotalDiscount(Double totalDiscount) {
        this.totalDiscount = totalDiscount;
    }
}
